Good afternoon,
I did what you (novacain) told (I didn't know how to do most of it, but I looked at MSDN and figured out), but I got stuck in one step. It is not an error, just something I couldn't figure out how to do.
First of all, let me show what I've already got (with the code below, I can click in the ListView items/SubItems and have the EditBox created, and destroyed when it looses focus).
I have a ListView (with LVS_EDITLABELS and LVS_REPORT styles), and created a Proc for it (ListViewProc), which looks for the WM_LBUTTONDOWN messages. Then, it uses SubItemHitTest to see which SubItem was clicked. Then, I use GetSubItemRect to create EditBoxs the same size as the SubItems.
The code below is the ListViewProc, with further explanations, just in case. The code below works fine.
Code:
long _stdcall ListViewProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_LBUTTONDOWN:
{
/*It uses SubItemHitTest to see which SubItem was clicked,
and stores it in the struct itemclicked.*/
long x, y;
x = (long)LOWORD(lParam);
y = (long)HIWORD(lParam);
LVHITTESTINFO itemclicked;
itemclicked.pt.x = x;
itemclicked.pt.y = y;
int lResult = ListView_SubItemHitTest(hwnd,&itemclicked);
/*If SubItemHitTest doesn't return any error (lResult!=-1), it gets the Rect
of the SubItem (or Item) clicked, and creates an EditBox (hEdit) with the
same size as the SubItem. Then, it sets focus on hEdit and sets a
callback function (EditProc) for it.*/
if (lResult!=-1){
RECT subitemrect;
ListView_GetSubItemRect(hwnd,itemclicked.iItem,itemclicked.iSubItem,LVIR_BOUNDS,&subitemrect);
int altura = subitemrect.bottom - subitemrect.top;
int largura = subitemrect.right - subitemrect.left;
if (itemclicked.iSubItem==0){largura=largura/4;}; /*NOTE: the ListView has 4 columns;
when iSubItem == 0 (an item is clicked),
the width (largura) is divided by 4,
because for items (not subitems) the
width returned is that of the whole row.*/
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD|WS_VISIBLE|ES_WANTRETURN,
subitemrect.left, subitemrect.top, largura, 1.5*altura, hwnd, 0, GetModuleHandle(NULL), NULL);
if(hEdit == NULL){MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);};
SetFocus(hEdit);
EOldProc = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)EditProc);
} else {
/*If SubItemHitTest does return error (lResult=-1),
it kills focus of hEdit in order to destroy it.*/
SendMessage(hEdit,WM_KILLFOCUS,0,0);
}
return 0;
break;
}
}
/*Other messages are sent to the original Proc
(LVOldProc), which is defined globally.*/
return CallWindowProc(LVOldProc, hwnd, message, wParam, lParam);
}
Then, there is the EditProc callback function, which hEdit uses to intercept WM_KILLFOCUS messages. The code is below.
Code:
long _stdcall EditProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_KILLFOCUS:
{
//Here, it needs to send the ListView a LVN_ENDLABELEDIT notification.
DestroyWindow(hwnd);
break;
}
}
return CallWindowProc(EOldProc, hwnd, message, wParam, lParam);
}
The problem is that, when hEdit looses focus, it needs to send the ListView a LVN_ENDLABELEDIT notification before it's destroyed (via DestroyWindow). I know that I have to set a LV_DISPINFO struct, but I have no idea how to start (I've looked at MSDN, but it got me confused).
I'm also not sure how the ListView will handle the notification (I know it's through WM_NOTIFY) and change the SubItem's text.
If you (or anyone) could help, I would appreciate it.
Thank you in advance for your patience.